home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 25 / Cream of the Crop 25.iso / doom / axxwar_1.zip / SOURCES / HARPOON.QC < prev    next >
Text File  |  1997-03-12  |  13KB  |  423 lines

  1. // AxxWars Release v1.0
  2. // Grapple.qc
  3. // Code used for the grappling harpoon
  4.  
  5. float() crandom;    // AXXGR
  6.  
  7.  
  8. /*
  9. =============
  10. Reset_Grapple
  11. =============
  12. */
  13. void (entity rhook) Reset_Grapple =
  14. {      sound (rhook.owner, CHAN_WEAPON, "weapons/bounce2.wav", 1, ATTN_NORM);
  15.         rhook.owner.on_hook = FALSE;
  16.         rhook.owner.hook_out = FALSE;
  17.         rhook.owner.fire_held_down = FALSE;
  18.         rhook.owner.weaponframe = 0;
  19.  
  20.         rhook.think = SUB_Remove;
  21.         rhook.nextthink = time;
  22. };
  23.  
  24. /*
  25. ==============
  26. Remove_Grapple
  27. ==============
  28. */
  29. void (entity rhook) Remove_Grapple =
  30. {
  31.         sound (rhook.owner, CHAN_WEAPON, "weapons/bounce2.wav", 1, ATTN_NORM);
  32.       centerprint (rhook.owner, "Your harpoon was pulled away!");
  33.         rhook.owner.on_hook = FALSE;
  34.         rhook.owner.hook_out = TRUE;
  35.       rhook.owner.hook_gone = TRUE;    
  36.         rhook.owner.fire_held_down = FALSE;
  37.         rhook.owner.weaponframe = 0;
  38.  
  39.         rhook.think = SUB_Remove;
  40.         rhook.nextthink = time;
  41. };
  42.  
  43. /*
  44. ===========
  45. RemoveChain
  46. ===========
  47. */
  48. void () Remove_Chain =
  49. {
  50.                 self.think = SUB_Remove;
  51.                 self.nextthink = time;
  52.  
  53.                 if (self.goalentity)
  54.                 {
  55.                         self.goalentity.think = SUB_Remove;
  56.                         self.goalentity.nextthink = time;
  57.  
  58.                         if (self.goalentity.goalentity)
  59.                         {
  60.                                 self.goalentity.goalentity.think = SUB_Remove;
  61.                                 self.goalentity.goalentity.nextthink = time;
  62.                         }
  63.                 }
  64.                 
  65. };
  66.  
  67. /*
  68. =============
  69. Grapple_Track
  70. =============
  71. */
  72.  
  73. void () Grapple_Track =
  74. {
  75.         local   vector  spray;
  76.  
  77.         // Release dead targets
  78.         if ((self.enemy.classname == "player") || (self.enemy.classname == "cbot")) 
  79.         if (self.enemy.health <= 0)    
  80.                 {
  81.                     self.owner.on_hook = FALSE;
  82.                     self.owner.attack_finished = time +0.50;
  83.                 }
  84.  
  85.         // drop the hook if owner is dead or has released the button
  86.         if (!self.owner.on_hook || self.owner.health <= 0)
  87.         {
  88.                 Reset_Grapple (self);
  89.                 return;
  90.         }
  91.  
  92.         // bring the pAiN!
  93.         if ((self.enemy.classname == "player") || (self.enemy.classname == "cbot"))
  94.         {        
  95.             // move the hook along with the player.  It's invisible, but
  96.             // we need this to make the sound come from the right spot
  97.             setorigin(self, self.enemy.origin);
  98.             
  99.             sound (self, CHAN_WEAPON, "blob/land1.wav", 1, ATTN_NORM);
  100.             Remove_Chain;
  101.             Remove_Grapple (self);
  102.             return;
  103.  
  104.             T_Damage (self.enemy, self, self.owner, 1);
  105.             makevectors (self.v_angle);
  106.             spray_x = 100 * crandom();
  107.             spray_y = 100 * crandom();
  108.             spray_z = 100 * crandom() + 50;
  109.             particle (self.enemy.origin, spray, 73, 20);// avoid a call to spawnblood
  110.               
  111.       }
  112.  
  113.         // If the hook is not attached to the player, constantly copy
  114.         // copy the target's velocity. Velocity copying DOES NOT work properly
  115.         // for a hooked client. 
  116.         if ((self.enemy.classname != "player") && (self.enemy.classname != "cbot"))
  117.                 self.velocity = self.enemy.velocity;
  118.  
  119.         self.nextthink = time + 0.1;
  120. };
  121.  
  122. /*
  123. ========
  124. MakeLink
  125. ========
  126. */
  127. entity (float head) MakeLink =
  128. {
  129.         newmis = spawn ();
  130.  
  131.         newmis.movetype = MOVETYPE_FLYMISSILE;
  132.         newmis.solid = SOLID_NOT;
  133.         newmis.owner = self;// SELF is the hook!
  134.  
  135.         newmis.avelocity = '200 200 200';
  136.  
  137.         setmodel (newmis, "progs/bit.mdl");
  138.         setorigin (newmis, self.origin);
  139.         setsize (newmis, '0 0 0' , '0 0 0');
  140.  
  141.         return  newmis;
  142. };
  143.  
  144. /*
  145. ============
  146. Update_Chain
  147. ============
  148. */
  149. void () Update_Chain =
  150. {
  151.         local   vector  temp;
  152.  
  153.         if (!self.owner.hook_out)
  154.         {
  155.                 self.think = Remove_Chain;
  156.                 self.nextthink = time;
  157.                 return;
  158.         }
  159.  
  160.         temp = (self.owner.hook.origin - self.owner.origin);
  161.  
  162.         // These numbers are correct assuming 3 links.
  163.         // 4 links would be *20 *40 *60 and *80
  164.         setorigin (self, self.owner.origin + temp * 0.25);
  165.         setorigin (self.goalentity, self.owner.origin + temp * 0.5);
  166.         setorigin (self.goalentity.goalentity, self.owner.origin + temp * 0.75);
  167.  
  168.         self.nextthink = time + 0.1;
  169. };
  170.  
  171. /*
  172. ===========
  173. Build_Chain
  174. ===========
  175. */
  176. void () Build_Chain =
  177. {
  178.         self.goalentity = MakeLink();
  179.         self.goalentity.think = Update_Chain;
  180.         self.goalentity.nextthink = time - 0.1;
  181.         self.goalentity.owner = self.owner;
  182.  
  183.         self.goalentity.goalentity = MakeLink();
  184.         self.goalentity.goalentity.goalentity = MakeLink();
  185. };
  186.  
  187. /*
  188. ==============
  189. Check_Overhead
  190. ==============
  191. */
  192. float () Check_Overhead =
  193. {
  194.         local   vector  src;
  195.         local   vector  end;
  196.  
  197.         makevectors (self.owner.angles);
  198.  
  199.         // The following comparisons could be optimized by doing away with
  200.         // SRC and END, and plugging the values directly into the traceline
  201.         // function calls. Using SRC and END made debugging easier. You
  202.         // decide if it's worth it.
  203.  
  204.         // quick check right above head
  205.         src = self.owner.origin - '0 0 24';
  206.         end = self.owner.origin - '0 0 24';
  207.         traceline (src, end, FALSE, self.owner);
  208.         if (trace_fraction != 1.0)
  209.                 return FALSE;
  210.  
  211.         src = self.owner.origin - '0 0 24' - v_forward * 16;
  212.         end = self.owner.origin - '0 0 24' - v_forward * 16 + '0 0 58';
  213.         traceline (src, end, FALSE, self.owner);
  214.         if (trace_fraction != 1.0)
  215.                 return FALSE;
  216.  
  217.         src = self.owner.origin - '0 0 24' + v_forward * 16;
  218.         end = self.owner.origin - '0 0 24' + v_forward * 16 + '0 0 58';
  219.         traceline (src, end, FALSE, self.owner);
  220.         if (trace_fraction != 1.0)
  221.                 return FALSE;
  222.  
  223.         src = self.owner.origin - '0 0 24' - v_right * 16;
  224.         end = self.owner.origin - '0 0 24' - v_right * 16 + '0 0 58';
  225.         traceline (src, end, FALSE, self.owner);
  226.         if (trace_fraction != 1.0)
  227.                 return FALSE;
  228.  
  229.         src = self.owner.origin - '0 0 24' + v_right * 16;
  230.         end = self.owner.origin - '0 0 24' + v_right * 16 + '0 0 58';
  231.         traceline (src, end, FALSE, self.owner);
  232.         if (trace_fraction != 1.0)
  233.                 return FALSE;
  234.  
  235.         return TRUE;
  236. };
  237.  
  238.  
  239. /*
  240. ==============
  241. Anchor_Grapple
  242. ==============
  243. */
  244. void () Anchor_Grapple =
  245. {
  246.         local   float   test;
  247.  
  248.         if (other == self.owner)
  249.                 return;
  250.  
  251.         // DO NOT allow the grapple to hook to any projectiles, no matter WHAT!
  252.         // if you create new types of projectiles, make sure you use one of the
  253.         // classnames below or write code to exclude your new classname so
  254.         // grapples will not stick to them.
  255.         if (other.classname == "missile" || other.classname == "grenade" || 
  256.             other.classname == "spike" || other.classname == "hook"
  257.             || other.classname == "pipebomb" )
  258.             return;
  259.  
  260.         // Don't stick the the sky.
  261.         if (pointcontents(self.origin) == CONTENT_SKY)
  262.         {
  263.                 Reset_Grapple (self);
  264.                 return;
  265.         }
  266.  
  267.         if ((other.classname == "player") || (other.classname == "cbot"))
  268.         {
  269.                 // glance off of teammates
  270.                 // if (other.steam == self.owner.steam)
  271.                 // return;
  272.             
  273.                 sound (self, CHAN_WEAPON, "player/axhit1.wav", 1, ATTN_NORM);
  274.                 T_Damage (other, self, self.owner, 25);
  275.  
  276.                 // make hook invisible since we will be pulling directly
  277.                 // towards the player the hook hit. Quakeworld makes it
  278.                 // too quirky to try to match hook's velocity with that of
  279.                 // the client that it hit. 
  280.         
  281.                     setmodel (self, "");
  282.         }
  283.         else if ((other.classname != "player") && (other.classname != "cbot"))
  284.         {
  285.                 sound (self, CHAN_WEAPON, "player/axhit2.wav", 1, ATTN_NORM);
  286.  
  287.                 // One point of damage inflicted upon impact. Subsequent
  288.                 // damage will only be done to PLAYERS... this way secret
  289.                 // doors and triggers will only be damaged once.
  290.                 if (other.takedamage)
  291.                         T_Damage (other, self, self.owner, 1);
  292.  
  293.                 self.velocity = '0 0 0';
  294.                 self.avelocity = '0 0 0';
  295.       }
  296.  
  297.         // conveniently clears the sound channel of the CHAIN1 sound,
  298.         // which is a looping sample and would continue to play. Tink1 is
  299.         // the least offensive choice, ass NULL.WAV loops and clogs the
  300.         // channel with silence
  301.         sound (self.owner, CHAN_WEAPON, "weapons/tink1.wav", 1, ATTN_NORM);
  302.  
  303.         if (!self.owner.button0)
  304.         {
  305.                 Reset_Grapple (self);
  306.                 return;
  307.         }
  308.  
  309.         // our last chance to avoid being picked up off of the ground.
  310.         // check over the client's head to make sure there is one unit
  311.         // clearance so we can lift him off of the ground.
  312.         test = Check_Overhead ();
  313.         if (!test)
  314.         {
  315.                 Reset_Grapple (self);
  316.                 return;
  317.         }
  318.  
  319.         self.owner.on_hook = TRUE;
  320.  
  321.         if (self.owner.flags & FL_ONGROUND)
  322.         {
  323.                 self.owner.flags = self.owner.flags - FL_ONGROUND;
  324.                 setorigin(self.owner,self.owner.origin + '0 0 1');
  325.         }
  326.  
  327.      //   sound (self.owner, CHAN_WEAPON, "weapons/chain2.wav", 1, ATTN_NORM);
  328.  
  329.         // CHAIN2 is a looping sample. Use LEFTY as a flag so that client.qc
  330.         // will know to only play the tink sound ONCE to clear the weapons
  331.         // sound channel. (Lefty is a leftover from AI.QC, so I reused it to
  332.         // avoid adding a field)
  333.         self.owner.lefty = TRUE;
  334.  
  335.         self.enemy = other;// remember this guy!
  336.         self.think = Grapple_Track;
  337.         self.nextthink = time;
  338.         self.solid = SOLID_NOT;
  339.         self.touch = SUB_Null;
  340. };
  341.  
  342.  
  343. /*
  344. =============
  345. Throw_Grapple
  346. =============
  347. */
  348. void () Throw_Grapple =
  349. {
  350.         sound (self, CHAN_WEAPON, "tw/twharp.wav", 1, ATTN_NORM); // ThunderWalker Change New sound for Harpoon gun
  351.  
  352.         if (self.hook_out)// reject subsequent calls from player.qc
  353.                 return;
  354.  
  355.  
  356. //        msg_entity = self;
  357. //    WriteByte (MSG_ONE, SVC_SMALLKICK);
  358.  
  359.         newmis = spawn();
  360.         newmis.movetype = MOVETYPE_FLYMISSILE;
  361.         newmis.solid = SOLID_BBOX;
  362.         newmis.owner = self;// newmis belongs to me
  363.         self.hook = newmis;// This is my newmis
  364.         newmis.classname = "hook";
  365.  
  366.         makevectors (self.v_angle);
  367.         newmis.velocity = v_forward * 1000;
  368.         newmis.angles = vectoangles(newmis.velocity); // ThunderWalker Change made missle point in direction shot
  369.  
  370.  
  371.         newmis.touch = Anchor_Grapple;
  372.         newmis.think = Build_Chain;
  373.         newmis.nextthink = time + 0.1;// don't jam newmis and links into same packet
  374.  
  375.         setmodel (newmis,"progs/twharp.mdl"); // ThunderWalker Change the harpoon model
  376.         setorigin (newmis, self.origin + v_forward * 16 + '0 0 16');
  377.         setsize(newmis, '0 0 0' , '0 0 0 ');
  378.  
  379.         self.hook_out = TRUE;
  380.         self.fire_held_down = TRUE;
  381. };
  382.  
  383. /*
  384. ===============
  385. Service_Grapple
  386. ===============
  387. */
  388. void () Service_Grapple =
  389. {
  390.         local   vector  hook_dir;
  391.  
  392.         // drop the hook if player lets go of button
  393.         if (!self.button0)
  394.         {
  395.                 self.fire_held_down = FALSE;
  396.                 if (self.weapon == IT_GRAPPLE)
  397.                 Reset_Grapple (self.hook);
  398.         }
  399.         // If hooked to a player, track them directly!
  400.         if ((self.hook.enemy.classname == "player") || (self.hook.enemy.classname == "cbot"))
  401.                 hook_dir = (self.hook.enemy.origin - self.origin);
  402.         // else, track to hook
  403.         else if ((self.hook.enemy.classname != "player") && (self.hook.enemy.classname != "cbot"))
  404.                 hook_dir = (self.hook.origin - self.origin);
  405.  
  406.         self.velocity = normalize(hook_dir) * 750;
  407.         if ( vlen(hook_dir) <= 100 && self.lefty)// cancel chain sound
  408.         {
  409.                 // If there is a chain, ditch it now. We're
  410.                 // close enough. Having extra entities lying around
  411.                 // is never a good idea.
  412.                 if (self.hook.goalentity)
  413.                 { 
  414.                         self.hook.goalentity.think = Remove_Chain;
  415.                         self.hook.goalentity.nextthink = time;
  416.                 }
  417.  
  418.     //    sound(self, CHAN_WEAPON, "weapons/chain3.wav", 1, ATTN_NORM);
  419.         self.lefty = FALSE;// we've reset the sound channel.
  420.         }
  421. };
  422.  
  423.